<?php

namespace StudyBuddy;

/**
 * Static class for setting and getting cookie(s)
 *
 */
class Cookie {

    /**
     * Function for setting or deleting login cookie
     * the value of the s cookie is an md5 hash of user password
     * the value of the uid cookie is the userID
     *
     * @param boolean $boolKeepSigned true if user checked 'remember me' box on login form
     * @param integer $intUserId userID
     * @param string $strPassword user's password
     * @return void cookies are sent to browser
     *
     */
    public static function sendLoginCookie($intUserId, $strSID, $cookieName = 'uid') {
        if (!is_numeric($intUserId)) {
            throw new DevException('wrong value of $intUserId param. Must be numeric. Was: ' . $intUserId);
        }

        /**
         * sid cookie is always sent out
         * this is a very important cookie
         * and will help us spot already registered user
         * who is also trying to either re-register
         * OR login with third party auth system like
         * Google Friend Connect or Facebook connect
         */
        $salt = STUDYBUDDY_COOKIE_SALT;
        $cookieSid = \hash('sha256', $intUserId . $salt);
        $cookie = \http_build_query(array('uid' => $intUserId, 's' => $cookieSid));

        self::set('sid', $strSID);
        self::set($cookieName, $cookie);
    }

    /**
     * Sends cookie
     *
     * @param string $name name of cookie
     *
     * @param string $val value of cookie
     *
     * @param string $ttl expiration time in seconds
     * default is 63072000 means 2 years
     *
     * @param string $sDomain optional if set the setcookie will use
     * this value instead of STUDYBUDDY_COOKIE_DOMAIN constant
     *
     * @throws StudyBuddyDevException in case cookie
     * was not send to browser. Usually this happends when
     * the output has already been started. The main cause
     * of this is when the script has an echo() or print_r()
     * somewhere for debugging purposes.
     */
    public static function set($name, $val, $ttl = 63072000, $sDomain = null) {

        if (headers_sent($filename, $linenum)) {
            e('Cannot set cookie: ' . $name . ' ' . $val . ' because headers have already been sent in ' . $filename . ' on line ' . $linenum);
            return;
        }

        $sDomain = (!empty($sDomain)) ? $sDomain : \trim(constant('STUDYBUDDY_COOKIE_DOMAIN')); // COOKIE_DOMAIN = "studybuddy.com.sg"
        $sDomain = (empty($sDomain) || 'null' === $sDomain) ? null : $sDomain;

        if($ttl < 0) {
            $t = mktime(0,0,0,1,1,1970);
        } else {
            $t = time() + $ttl;
        }

        if (false === $sent = \setcookie($name, $val, $t, '/', $sDomain, false, false)) {

            $err = 'Unable to send cookie: ' . $name . ' val ' . $val . ' ttl: ' . $ttl . ' time: ' . $t . ' domain: ' . $sDomain;
            e($err);
            throw new DevException($err);
        }

        return true;
    }

    /**
     * Sends cookie with expiration
     * in the past, which will delete the cookie
     *
     * @param mixed $name a string
     * or array of cookies to delete
     *
     * @throws StudyBuddyDevException if $name
     * is not string and not array
     *
     */
    public static function delete($name) {
        if (!is_string($name) && !is_array($name)) {
            throw new DevException('wrong type of $name param: ' . gettype($name));
        }

        $name = (is_string($name)) ? (array) $name : $name;


        foreach ($name as $val) {
//            self::set($val, false, -3600000);
            self::set($val, '', -3600000);
        }

        return true;
    }

    /**
     * Sends out the 'ref' cookie
     * if it has not already been set
     * and if user came from a website
     * different from currently viewed domain
     *
     *
     * @return void
     */
    public static function sendRefferrerCookie() {

        if (!isset($_COOKIE['ref']) && isset($_SERVER['HTTP_REFERER'])) {
            $strReferrer = $_SERVER['HTTP_REFERER'];
            $res = preg_match('@^(?:http(?:s*)://)?([^/]+)@i', $strReferrer, $matches);
            if (empty($res) || !is_array($matches) || empty($matches[1])) {
                d('cannot extract HTTP_REFERRER: ' . $_SERVER['HTTP_REFERER'] . ' $res: ' . $res);
                return;
            }

            $host = $matches[1];

            /**
             * If user came from a site other that this domain,
             * set referrer in SESSION
             */
            if (strtolower($_SERVER['HTTP_HOST']) !== strtolower($host)) {
                self::set('ref', $strReferrer);
            }
        }
    }

    /**
     * Sets the cookie 'sid' (first visit)
     * for about 6 years.
     * The value of 'sid' cookie starts with the timestamp
     * so we can always extract the first visit from it
     *
     * @return void
     */
    public static function sendFirstVisitCookie() {
        if (!isset($_COOKIE['sid'])) {
            self::set('sid', String::makeSid(), 189216000);
        }
    }

    /**
     * Returnes value of specific cookie name
     *
     * @param string $cookieName
     *
     * @param mixed $fallbackVal a value to return if cookie
     * does not exist or its value is empty
     *
     * @return mixed value if cookie found or false
     * if cookie not found
     */
    public static function get($cookieName, $fallbackVal = false) {
        if (!isset($_COOKIE) || empty($_COOKIE)) {

            return $fallbackVal;
        }

        $val = \filter_input(INPUT_COOKIE, $cookieName, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);

        return (empty($val)) ? $fallbackVal : $val;
    }

    /**
     * Returns value of first visit extracted
     * from sid cookie or false if sid cookie not present
     *
     * @param $bFirstVisitOnly if set to true then return
     * only the value of first visit, otherwise
     * return the value of sid cookie
     *
     * @return mixed int timestamp of first visit
     * or false if value not found in cookie
     */
    public static function getSidCookie($bFirstVisitOnly = false) {

        if (false === $sid = self::get('sid')) {

            return false;
        }

        $ts = substr($sid, 0, 10);

        /**
         * All first 10 chars must be numeric
         * or it's not a valid timestamp
         * it also means that our 'sid' cookie is
         * not valid and we should re-send it but...
         * but then we have a problem because sid cookie is tied to userID in
         * the database, so we can't just regenerate another sid
         * we must actually get it from the database for
         * the currently logged in user
         * at this point we don't even know if user is logged in or not,
         * so we will not do anything like resetting the sid cookie
         * but we will delete it just in case so as to prevent
         * the same problem
         *
         */
        if (preg_match('/\D/', $ts)) {
            e('StudyBuddyError sid cookie is not valid: ' . $sid);

            self::deleteCookie('sid');

            return false;
        }

        return ($bFirstVisitOnly) ? (int) $ts : $sid;
    }

}
